package org.peoplesearch.vk.executor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.*;
import java.util.*;

public class RoundProxySelector extends ProxySelector {

    final static Logger logger = LoggerFactory.getLogger(RoundProxySelector.class);

    class InnerProxy {
        Proxy proxy;
        SocketAddress addr;
        // How many times did we fail to reach this proxy?
        int failedCount = 0;

        InnerProxy(InetSocketAddress a) {
            addr = a;
            proxy = new Proxy(Proxy.Type.HTTP, a);
        }

        SocketAddress address() {
            return addr;
        }

        Proxy toProxy() {
            return proxy;
        }

        int failed() {
            return ++failedCount;
        }
    }

    HashMap<SocketAddress, InnerProxy> proxies = new HashMap<SocketAddress, InnerProxy>();
    List<SocketAddress> proxiesList = new LinkedList<SocketAddress>();
    private int lastId = -1;

    public RoundProxySelector(Collection<String> proxyStrings) {
        for (String proxyString : proxyStrings) {
            InnerProxy i = new InnerProxy(new InetSocketAddress(proxyString.split(":")[0], Integer.parseInt(proxyString.split(":")[1])));
            proxies.put(i.address(), i);
            proxiesList.add(i.address());
        }
    }

    public List<Proxy> select(URI uri) {
        if (proxiesList.size() == 0) {
            return new LinkedList<Proxy>(Collections.singleton(Proxy.NO_PROXY));
        }
        lastId++;
        if (lastId >= proxiesList.size()) {
            lastId = 0;
        }
        List<Proxy> result = new LinkedList<Proxy>();
        result.add(proxies.get(proxiesList.get(lastId)).toProxy());
        return result;
    }

    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
        if (uri == null || sa == null || ioe == null) {
            throw new IllegalArgumentException("Arguments can't be null.");
        }
        InnerProxy p = proxies.get(sa);
        if (p.failed() >= 3) {
            proxies.remove(sa);
            proxiesList.remove(sa);
            logger.debug("Was removed proxy " + sa);
            lastId--;
        }
    }
}
